perm filename MACHIN.DOC[NEW,AIL] blob sn#408299 filedate 1979-01-08 generic text, type T, neo UTF8
SAIL and PDP10 Machine Language                            January 26, 1976





                             Table of Contents
                             Table of Contents
                             Table of Contents
                             Table of Contents




Chapter                                                                Page

       Section



    List of Figures           .  .  .  .  .  .  .  .  .  .  .  .  .  .  iii


I.     SAIL and Machine Language .  .  .  .  .  .  .  .  .  .  .  .  .  . 1


II.    The PDP-10 Machine Language  .  .  .  .  .  .  .  .  .  .  .  .  . 2

       II.0   Introduction    .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 2

       II.1   Memory Architecture of the PDP-10 .  .  .  .  .  .  .  .  . 2

       II.2   A Note on Number Systems .  .  .  .  .  .  .  .  .  .  .  . 4

       II.3   The Word        .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 5

       II.4   Number Representation .  .  .  .  .  .  .  .  .  .  .  .  . 6

       II.5   Instruction Words  .  .  .  .  .  .  .  .  .  .  .  .  .  . 7

       II.6   Using DDT       .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 9

       II.7   Calculation of the Effective Address of an
                Instruction   .  .  .  .  .  .  .  .  .  .  .  .  .  .   11

       II.8   Immediate and Direct Instructions .  .  .  .  .  .  .  .   13

       II.9   Arithmetic Instructions  .  .  .  .  .  .  .  .  .  .  .   14

       II.10  Instructions Which Change the Program Counter .  .  .  .   14


III.   Some Examples of SAIL Code   .  .  .  .  .  .  .  .  .  .  .  .   17

       III.0  IF ... THEN     .  .  .  .  .  .  .  .  .  .  .  .  .  .   17

       III.1  DO, WHILE, and FOR Loops .  .  .  .  .  .  .  .  .  .  .   18

       III.2  Pushdown Instructions .  .  .  .  .  .  .  .  .  .  .  .   19


                                     i
SAIL and PDP10 Machine Language                            January 26, 1976





       III.3  SAIL Subroutine Calling Conventions  .  .  .  .  .  .  .   21

       III.4  Byte Pointers and SAIL Strings .  .  .  .  .  .  .  .  .   23

       III.5  Strings in Procedure Calls  .  .  .  .  .  .  .  .  .  .   28

       III.6  Array Implementation  .  .  .  .  .  .  .  .  .  .  .  .   29


    Appendix I

       Machine Instructions Commonly Used by SAIL  .  .  .  .  .  .  .   32








































                                    ii
SAIL and PDP10 Machine Language                            January 26, 1976





                              List of Figures
                              List of Figures
                              List of Figures
                              List of Figures






1.   Overall Hardware Configuration .  .  .  .  .  .  .  .  .  .  .  .  . 3


2.   Representation of Decimal Digets  .  .  .  .  .  .  .  .  .  .  .  . 5


3.   A Word                   .  .  .  .  .  .  .  .  .  .  .  .  .  .  . 5


4.   The Fields of an Instruction Word .  .  .  .  .  .  .  .  .  .  .  . 7



































                                    iii
SAIL and PDP10 Machine Language                            January 26, 1976





                                 Chapter I
                                 Chapter I
                                 Chapter I
                                 Chapter I

                         SAIL and Machine Language
                         SAIL and Machine Language
                         SAIL and Machine Language
                         SAIL and Machine Language




        The purpose of  these notes is to  discuss the relationship  of the
SAIL language  with the PDP-10  computer and its  machine language.   It is
intended to give a  better sense of the semantics  of SAIL in terms  of the
PDP-10,  thus assisting  in debugging,  and also  to provide  some  help in
interfacing machine language to the SAIL system.

        Chapter  II  discusses features  of  the PDP-10  relevant  to SAIL,
including some examples of SAIL compiled code and data structures.





































                                     1
SAIL and PDP10 Machine Language                            January 26, 1976





                                Chapter II
                                Chapter II
                                Chapter II
                                Chapter II

                        The PDP-10 Machine Language
                        The PDP-10 Machine Language
                        The PDP-10 Machine Language
                        The PDP-10 Machine Language






        II.0    Introduction
                Introduction
                Introduction
                Introduction


        What is machine language?  On our system this term could be used in
three senses:

        1)  The architecture of the central processing unit (CPU).

        2)  A  machine  language  assembler,  which  creates  and loads
    programs.  It  is usually  quite complicated.   There are  two main
    machine language assemblers used at IMSSS: FAIL and MACRO (1).

        3)  An  interpreter,  such   as  DDT.   Since  DDT   is  highly
    interactive it  is an  excellent starting  point for  learning more
    about CPU architecture,  assembly language, and  debugging compiled
    code.



        II.1    Memory Architecture of the PDP-10
                Memory Architecture of the PDP-10
                Memory Architecture of the PDP-10
                Memory Architecture of the PDP-10


        Figure 1 gives a  picture of the overall hardware  configuration of
the PDP-10.














------------
     (1)  There is  also a  third  available, called  MIDAS but  it  is not
maintained at IMSSS.


                                     2
SAIL and PDP10 Machine Language                            January 26, 1976






                        IMLAC   ...   IMLAC
                          |             |
                          |             |
                          |             |
                         HIGH-SPEED  LINES
                                 |
                                 |
                                 |
    -----------                  |
    |         |                  |
    | MAGTAPE |                  |
    |         |  ------------------------------------
    -----------  |                                  |
        |        |                     -----------  |
    --------     |              CPU    | ACCUMU- |  |    --------
    |      |     |                     | LATORS  |  |    |      |
    | DISK |-----|             (KI-10) -----------  |----| DRUM |
    |      |     |  -----------                     |    |      |
    --------     |  | "Hidden |                     |    --------
        |        |  | Memory" |                     |
    -----------  |  -----------                     |
    |         |  |                                  |
    | DECTAPE |  ------------------------------------
    |         |     |                            |
    -----------     |                            |
                    |                            |
                    |                            |
                    |                            |
                    |                            |
           MULTIPLEXING LINES               ----------
            |      |       |                |        |
            |      |       |                | MEMORY |
          TTY's   DM's   TEC'S              | (256K) |
                                            |        |
                                            ----------



                Figure  1.  Overall Hardware Configuration

        Some Remarks:

        1)  The accumulators may be thought of as high-speed memory.

        2)  The  "hidden  memory"  is  available  to  the  CPU,  but is
    transparent to the user.

        3)  The drum is used  in "swapping" and "paging"  operations so



                                     3
SAIL and PDP10 Machine Language                            January 26, 1976





    it serves  as a somewhat  slower memory.  The  drum at IMSSS  has a
    capacity  of  about  three million  36-bit  words.   If  this isn't
    enough, swapping will use the disk, which is considerable slower.

        4)  The IMSSS memory unit  has a capacity of 256K  words, where
         10
    K = 2  = 1024 (decimal).

        5)  Magtape  and Dectape  can be  thought of  as very  (!) slow
    forms of memory.

        6)  The  multiplexing lines  for TTY's,  TEC's, and  DM's avoid
    having the CPU look at each terminal separately to see if  there is
    any input from it.



        II.2    A Note on Number Systems
                A Note on Number Systems
                A Note on Number Systems
                A Note on Number Systems


        Most  readers  will  already  be  familiar  with  representation of
numbers in various  "bases", e.g. the  familiar decimal (base  10) notation
used everywhere except around computers, or binary notation using  just 0's
and  1's.  The  technical term  preferred by  many computer  scientists for
number base is radix.  Thus when balancing a checkbook, you are using radix
               radix
               radix
               radix
10 notation for  numbers.  There are two  others which are  convenient when
dealing with our system: radix 2 (binary) and radix 8 (octal).

        It can be somewhat confusing at first to keep track of  which radix
is being used in a  given context.  With experience, it will  become easier
to keep things straight.   For the time being I  will try to be  careful to
make it  clear what radix  is currently being  used.  There are  two common
conventions for indicating the radix:

        1)  A (decimal) subscript, e.g. 27∪10∩.

        2)  For radix 8, an apostrophe precedes the string of numerals,
    e.g.   the  octal  representation of  66  (decimal)  is  '102.  The
    apostrophe  convention  should  already  be  familiar  since  it is
    generally used when specifying the octal representation of an ASCII
    character.

        Context usually makes it clear when binary notation is  being used.
In this section the apostrophe convention will be used to indicate  radix 8
and,  in text  at least,  radix 10  should be  assumed.  However,  in later
chapters explicit mention will be made of the radix only where  there seems
a genuine danger  of confusion.  The next  figure gives the  decimal digets
and their binary and octal representations.




                                     4
SAIL and PDP10 Machine Language                            January 26, 1976






                  decimal   binary   octal
                  ------------------------
                     0         0        0
                     1         1        1
                     2        10        2
                     3        11        3
                     4       100        4
                     5       101        5
                     6       110        6
                     7       111        7
                     8      1000       10
                     9      1001       11


               Figure  2.  Representation of Decimal Digets



        II.3    The Word
                The Word
                The Word
                The Word


        The basic  unit of information  is called a  word; in the  PDP-10 a
                                                     word
                                                     word
                                                     word
word consists of  a string of  36 binary digits (either  0 or 1).   (In the
hardware there are 37, with the extra bit used to maintain parity; the user
never sees the parity bit.)


        II.3.1    Nomenclature
                  Nomenclature
                  Nomenclature
                  Nomenclature

        Regarding a word as a string of 36 binary digits or bits,  the bits
                                                            bits
                                                            bits
                                                            bits
are  numbered  from  left to  right  starting  with 0  and  ending  with 35
(decimal):

 -----------------------------------------------------------------------
 |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|
 -----------------------------------------------------------------------
  0                                   18                              35


                            Figure  3.  A Word

        Sometimes bits are also counted from the right.  In this case, they
are  grouped  into triples  (handy  when thinking  of  a word  as  an octal
number).  The rightmost bit is called  "the 1 bit", bit 34 is "the  2 bit",
33 is the "the 4 bit", 32 is  "the 10 bit", 31 is "the 20 bit", 30  is "the
40 bit" and so forth.  It is often convenient to think of a word as divided
into two half words of 18 bits each.  In this case the rightmost bit of the
left half word (bit 17) is also  called the 1 bit (of the left  half word).



                                     5
SAIL and PDP10 Machine Language                            January 26, 1976





Thus when context makes it clear that we are talking about the left half of
a word, bit 13 might be called the 20 bit.

        Since the rightmost digets of the number are the  least significant
(e.g. in terms of accuracy of  a measurement) the rightmost bits of  a word
are called the least significant bits.  These bits are also called  the low
               least significant bits                                   low
               least significant bits                                   low
               least significant bits                                   low
order bits, and bit 35 is THE low order bit.
order bits                    low order bit
order bits                    low order bit
order bits                    low order bit

        Finally, a byte  is any consecutive subpart  of a word which  is of
                   byte
                   byte
                   byte
one to thirty-five bits in length.


        II.3.2    Interpreting a Word
                  Interpreting a Word
                  Interpreting a Word
                  Interpreting a Word

        There are four ways of interpreting a word that will be of interest
to us:

        1)  Simply as a piece or pieces of stored information  or data.
    For example,  for reasons unknown  one could use  a single  word to
    store the  following information:  bits 0-2 encode  the day  of the
    week,  3-6  the  month,  4-11  the  date,  12-18  the  year  (to be
    interpreted as the last two decimal digets of the year),  19-23 the
    hour (24  hour clock),  24-29 the hour  (minutes), and  30-35 might
    give the number of one of 64 possible "canned" messages.

        2)  As  ASCII  text.   Since  there  are  '200  different ASCII
    characters  numbered from  '0  thru '177,  7 bits  are  required to
    represent one ASCII character.  But there are 36 bits in a word, so
    it is possible to store 5 ASCII characters in a word, with  one bit
    left over.  The convention used is that the low order bit  (bit 35)
    is ignored.

        3)  As a signed integer.

        4)  As a floating point (real) number.

        5)  And finally, a word can be interpreted as an instruction to
    the CPU.

        These last three will be discussed in more detail in  the following
sections.



        II.4    Number Representation
                Number Representation
                Number Representation
                Number Representation


        [A  section  on  integers, floating  point  numbers,  and  a little
arithmetic.]



                                     6
SAIL and PDP10 Machine Language                            January 26, 1976





        II.5    Instruction Words
                Instruction Words
                Instruction Words
                Instruction Words


        One  of  the  merits   of  the  PDP-10  instruction  set   is  that
"instruction words" have a very standard format.


        II.5.1    Fields
                  Fields
                  Fields
                  Fields

        When interpreted  as an  instruction, a word  is divided  into five
fields.  The left half of the word contains the first four of  these fields
fields
fields
fields
and the right half comprises the fifth.

    Location                   Name                   Remarks
(by bit number)
------------------------------------------------------------------------

     0 -  8             Opcode Field             The bit pattern for
                                                 the instruction

     9 - 12             Accumulator Field        Address of an
                                                 accumulator

       13               Indirect Address Bit     For indirect addressing
                                                 (See below)

    14 - 17             Index Register Field     Used in calculating the
                                                 effective address (See
                                                 below)

    18 - 35             Address Field



               Figure  4.  The Fields of an Instruction Word

        Each location in memory represents a single word.  Since we operate
under a timesharing  monitor and in a  paging environment, each user  has a
virtual PDP-10 with its full memory at his command. (2) Each word in memory
has an (octal) address ranging from '0 to '777777.

        NOTE:  All memory  locations will  ALWAYS be  referred to  as octal
numbers, not decimal.  In this  chapter we will usually remind you  of this
by using the "'" notation, but it will be dropped in subsequent chapters.

        The  first sixteen  locations  in memory  ('0 -  '17)  are somewhat

------------
     (2) And since it is possible to have several "forks" for the  same job
it is possible to have several copies of memory to work with if need be.


                                     7
SAIL and PDP10 Machine Language                            January 26, 1976





special.  '0 - '17 are sometimes  referred to as accumulators and '1  - '17
                                                 accumulators
                                                 accumulators
                                                 accumulators
as  index  registers.   Their  use  will  become  apparent  when  we  begin
    index  registers
    index  registers
    index  registers
discussing  particular  instructions.   They are  the  "high  speed" memory
referred to  earlier, and most  of the  "work" of the  computer is  done by
altering the contents of registers.

        We now discuss the five fields a bit more precisely.

        The  opcode field  contains  the number  of the  instruction  to be
executed.  Each number has a name, e.g., 254 is the JRST instruction.

        The address field is used  to store an address (i.e. a  location in
memory) which will be used by the particular instruction.

        The accumulator field  contains the address  of one of  the sixteen
accumulators.  Various instructions  can use this information  in different
ways.   One  typical use  is  as the  destination  for a  word  copied from
somewhere else in memory.

        The  indirect  address  bit  is  used  in  calculating  the address
actually  used  by the  instruction  according to  the  procedure described
below.

        The  index register  field is  used to  address one  of  the memory
locations '1-'17.  If  it is non-zero the  contents of the  addressed index
register are used  as part of the  calculation of the effective  address of
the  instruction.  Note:  In this  case, "contents  of the  index register"
means the contents of the RIGHT half word only.


        II.5.2    The Effective Address
                  The Effective Address
                  The Effective Address
                  The Effective Address

        Although  bits  18 - 35  comprise the  address  field,  ALL  of the
information contained in bits 13 - 35 is used to calculate the address used
by an instruction: In the following, let I be the contents of  the indirect
address bit (bit 13), X be the CONTENTS of the index register  specified in
the index register field (bits  14 - 17) (3), and let Y be the  contents of
the address field (bits 18 - 35).

        The address actually used by the instruction, called  the effective
                                                                  effective
                                                                  effective
                                                                  effective
address, is calculated by the  following recursive procedure: Add X  and Y.
address
address
address
(The result is, of course, an 18-bit binary number.) If I = 0, we are done.
But if  I = 1, go  to the  address X+Y, look  at bits  13 - 35 of  the word
contained there,  calculate a new  X and Y,  and then repeat  the procedure

------------
     (3) However, 0 is NEVER an index register -- if 0 occurs in  the index
register field of an instruction, then there simply is no index register.

     (4) Note that the process repeats until we find a word with I = 0.


                                     8
SAIL and PDP10 Machine Language                            January 26, 1976





(4).   The  address  X+Y  of  this  final  word  is  the  one  used  by the
instruction.  In the PDP-10 Reference Manual this final address  is denoted
by E.

        The value of E is ALWAYS calculated just as above.   In particular,
even  if the  instruction in  question does  not require  an address,  E is
calculated and  this value is  used by the  instruction in  the appropriate
fashion.  In other  words, whenever the indirect  address bit is 1,  X+Y is
interpreted as an address regardless of the nature of the instruction.



        II.6    Using DDT
                Using DDT
                Using DDT
                Using DDT


        With the preliminaries out of the way, we can begin  discussing DDT
(5).  To use DDT as an  interpreter, simply run DDT as you would  any other
program on <SUBSYS>:

@DD<CR>



        WARNING: When you  intend to use DDT  as an interpreter it  is very
important that you do a RESET  first to flush any program resident  in your
core image.  If you don't, things  will get a bit confusing and  should you
exit  and try  to continue  the system  will attempt  to execute  your (now
probably horribly smashed) copy of the program you were last using.

        DDT  greets  you in  a  very unassuming  fashion  by  returning two
carriage-returns.  No  message is  printed, but  once the  carriage returns
have been typed DDT is ready to accept commands.

        The first command to try  is "n/", where n is a  non-negative octal
integer not greater than '777777.  The effect of this command  is two-fold:
First, DDT will print out the  contents of address n (either as  a symbolic
instruction, or as an  octal number, depending).  Secondly, the  address is
opened  for writing,  i.e. you  can  alter the  contents of  address  n.  A
carriage return closes the address.  So to deposit the number 12 at address
100, you would type

            "100/"

and DDT would type  out the current contents  of address '100, or,  in case
your are starting with a "clean" core image, DDT will reply with a question
mark which is  its way of  telling you that this  address has not  yet been
used.  Then type

------------
     (5) Dynamic Debugging Technique.


                                     9
SAIL and PDP10 Machine Language                            January 26, 1976





            12<CR>.

        If you try "100/" now, DDT will print out "12".

        For the simple symbolic instructions that we will look at first, we
need not  worry about effective  addresses: What you  see is what  you get.
For the moment we can consider  an instruction word to be made up  of three
parts, namely an opcode, an accumulator field, and an address field.

        These will print out in the form

            OPCODE AC (6),Address

E.g.

            MOVE 1,100

        DDT will  also execute  instructions which are  given in  the above
format.  Simply type the instruction followed by "$X", where "$"  means hit
the ALT MODE (or ESC or ENTER) key.  "$X" tells DDT to execute  the command
you just typed,  and hitting the  ALT MODE key  will actually echo  on your
terminal as a "$".  In case you mistype an instruction, use the DELETE key.
It deletes the ENTIRE line you have typed, and echos at the terminal  as an
"XXX<CR>" sequence.

        We finish with a discussion of two instructions, MOVE and MOVEM.

        The MOVE instruction is  of the form MOVE AC,ADDRESS.   It's effect
is to copy  the contents of ADDRESS  into accumulator AC.  Thus  if address
100 contained 12  and you typed "MOVE  1,100$X" to DDT, then  accumulator 1
(which is at address 1 also) would now then contain "12".

        MOVEM AC,ADDRESS is the reverse of MOVE: it will take  the contents
of accumulator AC and copy it to ADDRESS.

        Exercises
        Exercises
        Exercises
        Exercises

        1)  Read  the  first  section in  the  PDP-10  System Reference
    Manual,  which  is  the  first  section  in  the  PDP-10  Reference
    Handbook.

        2)  A  word could  be thought  of as  a sequence  of thirty-six
    on/off switches  with each  switch corresponding to  a bit  and the
    "on" position represented by a  1.  Then we can talk  about turning
    on certain bits.  This  is often used in  the JSYS manual and  is a
    convenience when a  single word is used  to encode which of  a long
    list of options are desired--turning on the appropriate bit selects

------------
     (6) I.e. accumulator field


                                    10
SAIL and PDP10 Machine Language                            January 26, 1976





    the option or sets a  flag.  But since it is quite  inconvenient to
    type out a  string of thirty-six 0's  and 1's, radix 8  notation is
    generally used so that "only" twelve digets are  needed.  Question:
    What is the (octal) representation of a word in which the 2 bit, 10
    bit, 4000 bit and 200000 bit of the left half word are turned on?

        3)  What  is  the  representation  of  each  of  the  following
    integers as  a 36-bit word:  0,2,106,-1,106?  What is  the greatest
    positive  integer  expressible  as a  word?  The  greatest negative
    integer?

        4)  What is  the representation of  each of the  following REAL
    numbers: 0., 1.0,3.14159,106.,-106?

        5)  Why isn't accumulator '0 used as an index register?

        6)  Try the following commands in DDT: MOVE, MOVEM,  ADD, ADDM,
    SUB, SUBM.



        II.7    Calculation of the Effective Address of an Instruction
                Calculation of the Effective Address of an Instruction
                Calculation of the Effective Address of an Instruction
                Calculation of the Effective Address of an Instruction


        Since all (user) instructions have the same format, the PDP 10 is a
nice machine to deal with.  An important concept that we need is the notion
of the effective address of an instruction.
       effective address
       effective address
       effective address

        The  accumulators  '1  -  '17  are  sometimes  also  called  "INDEX
REGISTERS", and can be used  to help determine the effective address  of an
instruction.  Note that AC  0 is not on the  above list -- if it  were, the
contents of 0  would always be used  to calculate the effective  address of
any instruction which did not index one of the other AC's!!!

        We saw in the last lecture that one form of an instruction was like
MOVE  AC,100.  We  now look  at two  other forms.   The first  one includes
reference to an index register:  MOVE AC,100(1) for example.  In  this case
the effective address is calculated by adding the CONTENTS of register 1 to
100.

        Bit 13 of  an instruction is  called the indirect  bit.  Ordinarily
this bit is off.  If it is on, we write an "@" sign in the  instruction, as
in

        MOVE    AC,@100

The "@" causes the  indirect address bit to  be turned on, with  the result
that the instead of moving the contents of 100 into AC, the contents of 100
will be taken  to be an  address, and (provided bit  13 of that  address is



                                    11
SAIL and PDP10 Machine Language                            January 26, 1976





OFF)  the contents  of that  address will  be moved  to AC.   Some examples
should help to clarify this.

        Suppose the value of  AC1 is 10, the  value of location 100  is 50,
the value of 50 is  5, the value of 60 is  15, and the value of 110  is 60.
Then after executing Move 2,100 2 will contain 50.  After MOVE  2,100(1) it
will be 15,  after MOVE 2,@100  it will be 5,  and after MOVE  2,@100(1) it
will be 15.  Let's look at the last one closer.  By adding the  contents of
AC1 to 100 we get 110.  The contents of 110 is 60.  But indirect addressing
is in effect, so 60 is taken as an address rather than a value,  so looking
at 60 we  see that it contains  15.  But if we  changed the value of  60 to
20000015, or 20,,15 in half-word notation as DDT would usually  display it,
then the  indirect address bit  of 60 would  be "ON" as  you can  check for
yourself.  If we then did MOVE 2,@100(1), the value of 2 would be  0.  Why?
We obtain 60 as our second "intermediate" address.  But its indirect bit is
"ON" so we have to continue  calculating the address, which gives us  15 as
our next address.  But we assume 15 contains 0, so its indirect bit is off,
and we move its contents to AC2.

        REMARKS: i) DDT  will let you  write something like  MOVE 2,100(@)1
and  it will  try to  execute it.   But the  results will  NOT be  what you
expect.  (E.g. if you  are now in DDT  and have followed through  the above
sequence, put, say 7  into location 15 and  10 into location 10.   Try MOVE
2,100(@10).  See  what 2 contains.)  ii) More importantly,  it is  legal to
write an instruction like MOVE 100.   This is taken to be the same  as MOVE
0,100.   And  MOVE would  be  MOVE 0,0.   iii)  Note that  if  location 100
contained the instruction MOVE 1,@100, it could not be executed and the job
would "hang"  -- The  CPU is going  to insist  on calculating  an effective
address  (this is  always done  regard-less of  whether it  is used  by the
instruction or not!!).  But when it tries to do so it will loop.  And there
you will sit!!

        In practice in SAIL-compiled code, indirect addressing is  not used
especially  often,  the  main   use  being  for  REFERENCE   parameters  to
procedures.  And the  most frequent use of  indexing is in  connection with
arrays.

        A location in  memory (and this  includes the accumulators)  can be
given  a  symbolic name  or  LABEL.  When  we  are using  ONLY  the (octal)
addresses of words in memory  we speak of ABSOLUTE ADDRESSING, and  when we
are allowed  to use labels  we speak of  symbolic addressing.  To  assign a
label to an  address you can  open that address  for writing using  "/" and
then type the  label (up to  six characters) followed  by a ":".   DDT will
answer by moving the  cursor (on a DPY)  two spaces.  This will  not change
the contents of that address, though if you wish you can insert a new value
at this time since the address is still open for writing.  A <CR>  will, as
usual, close the word for writing.  Suppose you called location 100 FOOBAZ.
Typing "FOOBAZ/"  to DDT will  now have exactly  the same effect  as typing
"100/", executing MOVE 1,FOOBAZ(2)  will have the same effect  as executing
MOVE 1,100(1) and so forth.


                                    12
SAIL and PDP10 Machine Language                            January 26, 1976





        A linefeed (<LF>) typed to DDT in place of a <CR> when you  have an
address open  for writing  will take  the following  actions: i)  close the
current location just like a <CR> and ii) open the next address for writing
(just like a /).

        A "↑"  works just  like a <LF>  except that  it opens  the previous
address  for  writing  rather  than  the  following  (i.e. higher-numbered)
address.

        One-dimensional arrays are easily  constructed.  To do so,  you can
open an address, say 100, for  writing and then store the first  element of
the array  there, the next  element in the  following location, and  so on.
Try the following.  Note: the  periods after the integers tell DDT  to take
those integers as being decimal rather than octal!

        2/ J: <CR>

        100/ A: 2. <LF>

        A+1/ 4.  <LF>

        A+2/ 6.  <LF>

        A+3/ 8.  <LF>

        A+4/ 10.  <CR>

        200/ I: 3 <CR>

        Now  try  executing the  following  two instructions  and  see what
happens: MOVE 1,I ; Don't forget to type $X to execute!  MOVE J,A(1)

        If you do  this on-line you will  have constructed an  array A[0:4]
(about like the SAIL compiler would), and the two instructions you executed
would have had the same effect as "J ← A[I];" in SAIL, where a "I ← 3;" had
just been done.

        We  will look  more  closely at  the array  implementation  in SAIL
later.



        II.8    Immediate and Direct Instructions
                Immediate and Direct Instructions
                Immediate and Direct Instructions
                Immediate and Direct Instructions


        Once we have computed the effective address of an instruction there
are two ways of dealing with it.  The way we have seen so far is called the
"direct"  use, i.e.  take  the effective  address  and interpret  it  as an
address.   However, the  effective  address can  also be  interpreted  as a
number.  In this case we speak of an "immediate" instruction.


                                    13
SAIL and PDP10 Machine Language                            January 26, 1976





        Many of the PDP-10 machine instructions contain the letter  "I" for
"immediate".  E.g. MOVEI  2,100 is an  instruction.  It will  calculate the
effective address, 100 in this case, and move it, rather than its contents,
into AC2.  Thus,  if location 100 contains  506, then in this  special case
both MOVE 1,100 and MOVEI 1,506 would deposit 506 in AC1.  Again, note that
in an "immediate" instruction it  is the EFFECTIVE ADDRESS rather  than its
contents which  is used in  the instruction.  Thus  if 1 contains  10, then
MOVEI 2,506(1) would fetch 516 into AC2.

        The SAIL statement

I ← J;

would compile as
                MOVE  1,J
                MOVEM 1,I

while

I ← 6;

would compile as

                MOVEI 1,6
                MOVEM 1,I




        II.9    Arithmetic Instructions
                Arithmetic Instructions
                Arithmetic Instructions
                Arithmetic Instructions


        Four  more   simple  instructions:   MUL,DIV,IMUL,  and   IDIV  for
multiplication and division.  NOTE: In the case of IDIV  (integer division)
an instruction like IDIV AC,Mem  will put the integer portion  of (contents
of AC divided by contents of Mem) into AC and the (integer)  remainder into
AC + 1.



        II.10    Instructions Which Change the Program Counter
                 Instructions Which Change the Program Counter
                 Instructions Which Change the Program Counter
                 Instructions Which Change the Program Counter


JRST (Jump and ReSTore flags):
JRST
JRST
JRST


        An unconditional jump.  Given in  the form JRST Loc.  It  takes you
to the address with (symbolic) name Loc without further ado.

JUMPsuffix AC,Loc:
JUMPsuffix
JUMPsuffix
JUMPsuffix


                                    14
SAIL and PDP10 Machine Language                            January 26, 1976





        Comes  in  8 varietics,  depending  upon the  suffix.   JUMP itself
(i.e., no suffix) is a no-op.  The suffix list is:

        no suffix       No-op
        E               Equal
        N               Not equal
        GE              Greater than or Equal
        G               Greater than
        L               Less than
        LE              Less than or Equal
        A               Always

These 8 suffixes are important in the PDP10 instruction set, for  they test
the value  of the  accumulator relative  to 0  (e.g., is  the value  of the
accumulator Greater than or Equal to 0 means GE), using that test to decide
whether or not to perform some action.  For example,

JUMPGE  AC,LOC

jump  to LOC  and continue  the program  there if  the contents  of  AC are
Greater  or Equal  to zero,  and if  not goes  to the  next  instruction in
sequence.

        Forgetting a  suffix on the  JUMP means JUMP  never --  i.e., don't
JUMP.  Using the A suffix -- JUMPA -- means JUMP always.  The instruction

JUMPA ac,loc

is the same as JRST; JRST is faster.

SKIPsuffix AC,Loc:
SKIPsuffix
SKIPsuffix
SKIPsuffix


        Takes same suffixes as  JUMP (including A).  SKIP and  its variants
compare the contents of Loc with 0 and if the condition is  satisfied skips
the next instruction.  Thus,

SKIPA
JRST    LOC1
JRST    LOC2

simply skips over the JRST LOC1 instruction and executes JRST LOC2.

        If the accumulator field of the SKIP instruction is not accumulator
0,  then  the  contents  of  the  effective  address  are  moved  into  the
accumulator before  the test.  This  instruction can be  used to do  both a
fetch and a test  on a value at one  time.  The SAIL compiler does  not use
this ability as often as it might.

CAMsuffix AC,Loc (Compare Ac with Memory):
CAMsuffix
CAMsuffix
CAMsuffix


                                    15
SAIL and PDP10 Machine Language                            January 26, 1976





        Compares contents of AC with contents of Loc and skip next instr if
condition satisfied.  Same 8 suffixes as JUMP.  Thus CAME AC,Loc  will skip
the next instr in sequence if contents of AC is same as contents of Loc.

CAIsuffix AC,Loc (Compare Ac Immediate):
CAIsuffix
CAIsuffix
CAIsuffix


        Like CAM, but is an  immediate as opposed to a  direct instruction.
Compares the contents of AC with Loc as opposed to the value of Loc.











































                                    16
SAIL and PDP10 Machine Language                            January 26, 1976





                                Chapter III
                                Chapter III
                                Chapter III
                                Chapter III

                        Some Examples of SAIL Code
                        Some Examples of SAIL Code
                        Some Examples of SAIL Code
                        Some Examples of SAIL Code




        It is now possible to give some canonical code schemata for various
SAIL  constructions.   Doing  this  has three  purposes:  it  gives  a more
concrete characterization to the meaning of the SAIL construction; it makes
concrete the meaning of the PDP10 instructions by giving some examples; and
assists in debugging one's programs.



        III.0    IF ... THEN
                 IF ... THEN
                 IF ... THEN
                 IF ... THEN


        The statement

IF I GEQ 0 THEN S1

will compile

        SKIPGE  I               ;test I GEQ 0
          JRST  BEYOND          ;nope, its not
        S2
        .
        .
        .
BEYOND:
[Remark: In these and other examples, labels like BEYOND, LOOP, are made up
here for  purposes of demonstration.   In general, there  will not  be such
labels  in  your core  image  unless  you have  specifically  used  them as
identifiers in your program.  Also,  the S2... indicates that the  code for
S2 (whatever it is) gets compiled at that point.

        Also, these  examples are  only meant to  be representative  of the
actual code.  In some cases,  depending on context, the actual code  may be
different.   For  example,  if a  value  is  known to  be  in  a particular
accumulator, then the code to fetch it can be omitted.]

        The statement

IF I LEQ 0 THEN S1 ELSE S2

becomes

        SKIPLE  I                       ;is I less than or equal to 0
          JRST  DOS2                    ;no, go do S2


                                    17
SAIL and PDP10 Machine Language                            January 26, 1976





        S1
        .
        .
        .
        JRST    BEYOND                  ;and jump around S2 code
DOS2:   S2
        .
        .
        .
BEYOND:




        III.1    DO, WHILE, and FOR Loops
                 DO, WHILE, and FOR Loops
                 DO, WHILE, and FOR Loops
                 DO, WHILE, and FOR Loops


        Several other ALGOL loops are given in the following:

WHILE I < 0 DO S1

compiles to

        SKIPL   I
          JRST  BEYOND
        S1
        .
        .
        .
BEYOND:

The statement


WHILE I < J DO S1

compiles to

        MOVE    AC,I                    ;fetch I into AC
        CAML    AC,J                    ;check whether I < J
          JRST  BEYOND
        S1
        .
        .
        .
BEYOND:

Notice, in comparing the above two examples, that the compiler  selects the
most  efficient  test  possible.   In  the  first  WHILE  loop,  the  SKIPL



                                    18
SAIL and PDP10 Machine Language                            January 26, 1976





instruction will test whether I is  less than 0; in the second  WHILE loop,
it  is necessary  to use  two instruction,  one to  fetch a  value  into an
accumulator,  the other  to  make the  test.  The  compiler  performs local
optimizations of this kind.

        The FOR loop:

FOR I ← 1 STEP 1 UNTIL 10 DO S1

becomes

        MOVEI   AC,1                    ;set initial value of I
LOOP:   MOVEM   AC,I
        CAILE   AC,12                   ;10 decimal is 12 octal
        S1
        .
        .
        .
        MOVE    AC,I                    ;get I back into AC
        AOJA    AC,LOOP                 ;Add One to ac and Jump Always
BEYOND:

If the loop had been "STEP -1" then the last instruction would have been an
SOJA -- Subtract One from ac and Jump Always.

        The DO...UNTIL:

DO S1 UNTIL J = 0;

compiles to

LOOP:   S1
        .
        .
        .
        SKIPE   J
        JRST    LOOP

"DO ... UNTIL" sometimes makes more elegant code than  logically equivalent
"WHILE" statements, often allowing one fewer instruction.



        III.2    Pushdown Instructions
                 Pushdown Instructions
                 Pushdown Instructions
                 Pushdown Instructions


        There are four basic pushdown list instructions: PUSH,  PUSHJ, POP,
and POPJ.  They have the usual format, e.g. PUSH AC,Loc.




                                    19
SAIL and PDP10 Machine Language                            January 26, 1976





        The AC referenced in the instruction is a POINTER into the pushdown
stack.  This pointer is a word,  the left half of which contains  the stack
counter and  the address of  the current top  of the stack.   The effective
address of the word which is at the top is the address of whatever word can
be thought of as being "stored" on the stack at that point.   This probably
isn't  very clear  yet, but  the following  diagram and  an example  or two
should help to clarify.

        Internally,  a  pushdown stack  consists  of the  POINTER  and some
consecutive section in memory, with the higher addresses being further down
on the stack:

        ------------    "bottom" of stack
        ------------
        ------------
        ------------
        ------------
        ------------    "top" of stack (the pointer "points" here)
        ------------
        ------------
        ------------


        To use a pushdown stack you have to set it up.  To do so  you first
choose an accumulator.  The usual choice here is traditionally 17, which is
usually called  P for  "pointer".  SAIL  uses accumulator  17 for  its main
control stack, and it is called P.  (There are two other registers  in SAIL
that deal with push-down lists, SP  (16) for strings, and RF (12)  which is
another pointer into the same stack  that P points to.  P is loaded  with a
word, the left half of which is the negative of an integer n, which will be
the maximal number of elements that can go on the stack.  The right half is
the address of the  initial top of the stack.   (To begin with, it  is also
the  "bottom" of  the stack.)  That address  Addr to  address Addr  + (n-1)
should now be regarded as being reserved for the pushdown stack.  Normally,
these addresses shouldn't be altered except by use of the four instructions
mentioned earlier.  Note: if you accidentally try to add too  many elements
to the stack, it is called  "pushdown overflow" and if you try to  take too
many off (e.g. by trying to  take something off before anything was  put on
the stack), it is called "pushdown underflow".

        Suppose WORD is a symbolic address containing -n,,start of stack

        Then MOVE P,WORD (P as above) will set up AC 17 as a pushdown stack
which can contain up to n  elements and which will run from  location start
of stack to start of stack +(n-1).  The SAIL stack comes already set  up as
a stack by the SAIL runtime system.

        Let I  be a  symbolic address.   The instruction  PUSH P,I  has the
following effects after execution:



                                    20
SAIL and PDP10 Machine Language                            January 26, 1976





            1)  P  will  now contain  -n-1  (i.e.  -(n+1),,start of
        stack + 1.

            2)  The effective address  calculated from the  word at
        start  of stack  +  1 will  be  a cell  which  contains the
        contents of I.

        Note: PUSH has side effects since the contents of start of  stack +
1 have been changed.

        POP is the compliment of  PUSH.  POP P,J will take the  contents of
the current item on the stack and store it in location J.  It also alters P
so that it points one element lower in the stack.

        PUSHJ (PUSH and Jump): PUSHJ P,SUBR would put the return address on
the stack  and jump to  loc SUBR, continuing  execution from  there.  PUSHJ
increments the pointer by 1 (i.e. changes P from -n,,addr to -n+1,,addr+1),
stores the current PC (Program  Counter), i.e. current location on  the top
of  the  stack,  and continues  at  loc  SUBR.  It  is  used  to  execute a
subroutine then return and continue execution.

        POPJ reads the top element of the stack (making the next  one below
the new "top") and jumps to the location it specifies, continuing execution
of the program there.  So PUSHJ lets us execute a subroutine; when finished
a  POPJ will  let us  continue on  where we  were when  the  subroutine was
called.



        III.3    SAIL Subroutine Calling Conventions
                 SAIL Subroutine Calling Conventions
                 SAIL Subroutine Calling Conventions
                 SAIL Subroutine Calling Conventions


        NOTE: THIS SECTION IS A SLIGHT OVERSIMPLIFICATION!

        We shall  examine here  a simplified  version of  the code  for the
FACTORIAL function.  The point of the example is to see how push-down lists
are used to implement SAIL subroutines.

        SAIL subroutines  calls work  by pushing  their arguments  with the
PUSH  instruction,  in  order,  onto the  P  stack,  and  then  calling the
subroutine with a  PUSHJ.  Values returned by  a procedure are  returned in
accumulator 1, which is called A.

        Hence, suppose we have a procedure with the declaration:

INTEGER PROCEDURE F(INTEGER I,J); body of declaration

Then, the statement

I ← F(B,C)


                                    21
SAIL and PDP10 Machine Language                            January 26, 1976





would compile as

        PUSH    P,B                     ;put B argument on the stack
        PUSH    P,C                     ;put C argument on the stack
        PUSHJ   P,F                     ;call function
        MOVEM   A,I                     ;store from ac A into cell I

Composed function calls are performed by sequences of
PUSHes and PUSHJ's.  Thus,

I ← F(F(B,C),F(D,E))

would compile

        PUSH    P,B
        PUSH    P,C
        PUSHJ   P,F                     ;compute F(B,C)
        PUSH    P,A                     ;save result on stack
        PUSH    P,D
        PUSH    P,E
        PUSHJ   P,F                     ;compute F(D,E)
        PUSH    P,A                     ;stack now
                                        ;contains the two arguments
        PUSHJ   P,F                     ;compute F(F(B,C),F(D,E))
        MOVEM   A,I                     ;store result

Notice that the  stack is adjusted correctly  after this call --  i.e., the
stack  pointer  is  the  same  at the  end  as  it  was  at  the beginning.
Otherwise,  we would  face serious  problems.  A  common error  in machine-
coding is getting the stack out of sync.

        Let's look at  a sample program,  which will calculate  a factorial
using the SAIL procedure:
RECURSIVE INTEGER PROCEDURE FACT(INTEGER I);
RETURN(IF I LEQ 0 THEN 1 ELSE FACT(I * FACT(I-1));

which might compile something like

FACT:   SKIPG   A,-1(P)                 ;aha -- argument is here
          JRST  RET1                    ;I is LEQ 0
        SUBI    A,1                     ;I - 1
        PUSH    P,A                     ;call
        PUSHJ   P,FACT                  ;FACT(I-1)
        IMUL    A,-1(P)                 ;I * FACT(I - 1)
RETURN: SUB     P,[2000002]             ;adjust the stack
        JRST    @2(P)                   ;and return
RET1:   MOVEI   A,1                     ;RETURN(1)
        JRST    RETURN




                                    22
SAIL and PDP10 Machine Language                            January 26, 1976





(Actually this code is more  like a SAIL SIMPLE procedure than  a RECURSIVE
one; this is the oversimplification.)

        There are two important things about this procedure.  First, the "-
1(P)" is a memory access using P (the stack pointer) as an  index register.
It FETCHES THE LAST ARGUMENT TO THE PROCEDURE.

        Consider  the state  of the  stack coming  into the  procedure.  It
looks like:

        argument
        return address          --- P points here


Thus, (P)  is the  address of the  return address,  -1(P) fetches  the last
argument, -2(p) fetches the next to the last argument, etc.   (Value string
arguments are handled differently.) Whenever SAIL compiles code that refers
to -n(P), it is accessing an argument to a SIMPLE procedure.

        Secondly,  the two  instructions at  RETURN are  for  adjusting the
stack and  returning.  The  first instruction removes  two things  from the
stack, by subtracting 2 from both sides of the stack.  The JRST  returns to
the next instruction in sequence.  These two instructions are found  at the
end  of  a typical  SAIL  procedure.   If there  are  n  (non-VALUE STRING)
arguments, then the number 2 becomes n+1 in these two instructions.



        III.4    Byte Pointers and SAIL Strings
                 Byte Pointers and SAIL Strings
                 Byte Pointers and SAIL Strings
                 Byte Pointers and SAIL Strings


        Strings  are  arbitrarily  long lists  of  ASCII  characters.  SAIL
strings  are actually  a unit  of  2 consecutive  words known  as  a string
                                                                     string
                                                                     string
                                                                     string
descriptor.  The two words look like:
descriptor
descriptor
descriptor

S:      XWD DYNAMIC,COUNT
        BP

XWD means that DYNAMIC and COUNT  are half words of the first  word.  COUNT
is  the number  of characters  in the  string; DYNAMIC  is non-zero  if the
string was created dynamically (e.g., by concatenating), zero if the string
is a constant string (which therefore does not require garbage collection).
BP is a PDP-10 byte pointer to the first character of the string.

        We now  discuss the  notion of a  byte-pointer. Sometimes  we don't
want to  use a full  word or half  word.  For example,  it takes 7  bits to
store one ASCII  character and since  there are 36 bits  in a word,  we can
store 7  ASCII characters  (with a bit  left over).   There are  also cases
where one  wants to use  other sizes of  storage; 6, 8,  9, and 12  are all
common units.


                                    23
SAIL and PDP10 Machine Language                            January 26, 1976





        Any fraction of a word between 1 and 35 bits in length is  called a
BYTE.  In the following, we assume that we are not interested in  bytes the
length of which can  change from one byte to  the next, but rather  that we
know  how  long  a  byte  will be.   Given  this,  we  need  two  pieces of
information to store or retrieve an arbitrary number of bytes,  in addition
to the effective address of the word: i) the length of a byte and ii) where
in a word the "current"  byte starts.  This is enough information  to allow
us to retrieve the current byte or to store another byte directly following
the current byte.

        These two  pieces of  information are stored  in a  "byte pointer".
Internally, a  byte pointer is  a word in  which bits 0-5  tell us  the bit
number within the storage word at which the current byte starts (call these
bits P) and  bits 6-11 tell  us the size (i.e.  length) of that  byte (call
bits 6-11 S).  Bits 13-35 perform their usual addressing functions, and the
effective  address  calculated  from  them  is  the  address  of  the  word
containing the current byte.

        HOWEVER,  P  is not  the  bit  number where  the  byte  starts.  To
facilitate  the case  where we  have a  consecutive series  of  bytes which
occupy more than  one word, P  is actually the  number of "free"  or unused
bits in a word.  This  makes it easy to modify  P so that it points  to the
next bit to the right: If S is the length of the current byte then P-S will
now point to the location of the next byte.  Note that by assuming S  to be
a constant,  we can alter  the pointer simply  by performing  the indicated
subtraction.  Furthermore, if  P-S < 0, we  know that we don't  have enough
room in the storage word to put another byte of length S.  In this  case, P
can be set to 0 and the  right half of the byte pointer can  be incremented
by 1 so that the effective address will now be the old effective address+1.
Thus, our byte pointer now will go looking in the next word to fetch a byte
or starting writing  in the next  word to store  a byte.  (This  might seem
like a waste of space; suppose  you wanted to store 8-bit bytes.   Then you
would waste 4 bits in every word of byte storage.  The KL-10 is  rumored to
have some new instructions that make byte-stream storage possible.)

        The following two diagrams, due to Scott Daniels, illustrate  how a
byte pointer is constructed and how bytes are stored in a word:















                                    24
SAIL and PDP10 Machine Language                            January 26, 1976






                        BYTE POINTER


 POSITION  |    SIZE   | |I| INDEX ||          WORD ADDRESS             |
-----------|-----------|-|-|-------||-----------------------------------|
0|0|0|0|0|0|0|0|0|0|1|1|1|1|1|1|1|1||1|1|2|2|2|2|2|2|2|2|2|2|3|3|3|3|3|3|
0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|6|7||8|9|0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|
-----------|-----------|-|-|-------||-----------------------------------|
    (P)    |     (S)   | | |       ||                                   |

                        BYTE STORAGE
---------------------------------------|------------|------------|------|
                                       |    BYTE    | NEXT  BYTE |      |
---------------------------------------|------------|------------|------|
<========35 - (S) - (P) BITS==========>|<=(S) BITS=>|<====(P) BITS=====>|


        So, now that we have a scheme for keeping track of where  our bytes
will go, what instructions do  we have for doing byte  manipulation?  There
are five: (Assume below that the byte pointer has symbolic name BP.)

IBP  BP    -- This simply Incriments the Byte Pointer.

LDB  AC,BP -- BP is the address of a word that is a byte pointer.  The
        byte pointed to is fetched into AC.

DPB  AC,BP -- BP is the address of a word that is a byte pointer.  The
        contents of AC are deposited into that byte.  (High-order bits
        are removed from the contents of AC.)

ILDB AC,BP -- This instruction FIRST incriments the byte pointer, then
        takes the same actions as LDB.

IDPB AC,BP -- First incriments the byte pointer, then does a DPB.


        In SAIL, there is a  function called POINT that will create  a byte
pointer for you.  The  call is of the  form BP←POINT(x,I,y) where BP  and I
are declared to be  integer.  BP is the byte  pointer, I is the  address of
the (first) word containing the bytes, x is the number of bits in  the byte
and y  is an integer  called the "last  bit number".  In  case x is  7, you
might want to use  6 for y, provided you  are using LDP to read  the bytes.
Otherwise, and this holds regardless of the value of x, use -1 for  y which
will insure that ILDB will do the right thing on its initial call.  In FAIL
and MACRO there are pseudo-ops that create bytepointers at assembly time.

        In  SAIL, the  following code  (where TBP,NBP,TEXT,  and  NTEXT are
declared to be of type INTEGER)  would transfer a 5 byte long  7-bit string



                                    25
SAIL and PDP10 Machine Language                            January 26, 1976





stored left-justified in TEXT to  NTEXT, where TEXT and NTEXT  are declared
INTEGER, as well as the iteration variable I.

TBP ← POINT(7,TEXT,-1);
NBP ← POINT(7,NTEXT,-1);
FOR I ← 1 STEP 1 UNTIL 5 DO IDBP(ILDB(TBP),NBP);


        What  does the  SAIL  compiler do  with a  string  declaration like
"STRING S;" ?  This assembles as  two instructions, say  S which is  of the
form

               -------------------
               |DYNAMIC |  COUNT |
               -------------------

and a second, say S+1, which is of the form
               --------------------------
               | BP pointer to 1st byte |
               --------------------------

(The word DYNAMIC is non-zero just in case the string is dynamic.)

        The SAIL  function LENGTH(S)  compiles as HRRZ  AC,S (S  as above).
Since this is the first time we have seen half-word instructions we digress
for a moment to introduce some of the more common ones:

        The "H" is the mnemonic  for "Half-word", "L" for "Left half  (of a
word), "R" for "Right half", "Z" for all 0's, "O" for "all 1's, and I and M
as usual.  Then some of the possibilities are:

      FROM  TO   REST OF DESINATION
      ----  --   ------------------
       R     R          Z               I
   H
       L     L          O               M


        So, for example, HLRO AC,Loc  would copy the left half of  the word
at Loc (assuming bit 13 is off, of course) to the right half of AC, filling
the left half of AC with 1's.

        A string assignment statement

S ← T;

where S and T are strings, might (but doesn't) compile as

        MOVE    AC,T
        MOVEM   AC,S


                                    26
SAIL and PDP10 Machine Language                            January 26, 1976





        MOVE    AC,T+1
        MOVEM   AC,S+1

In fact, it compiles as

        HRROI   AC,T+1
        POP     AC,S+1
        POP     AC,S

which is  one fewer  instruction!!  It works  by making  AC be  a temporary
push-down  pointer and  then POPes  the string,  thus moving  it.   This is
another of the (relatively few) tricks that are used by the SAIL compiler.

        Thus the SAIL code

I ← LENGTH(S)

is compiled as

        HRRZ    AC,S
        MOVEM   AC,I

LENGTH has the  syntax of a subroutine,  but no subroutine call  is emitted
here.   We say  that  LENGTH compiles  open.   The opposite  is  to compile
                             compiles  open                         compile
                             compiles  open                         compile
                             compiles  open                         compile
closed.
closed
closed
closed

        The SAIL LOP function for a string:

I ← LOP(S)

compiles as

        HRRZ    AC,S            ; Store length of string in AC
        JUMPE   AC,DONE         ; If length = 0, then finished
        SUBI    AC,1            ; Decrement the count
        HRRZM   AC,S            ; and store in count field
        ILDB    AC,S+1          ; S+1 as above
DONE:   MOVEM   AC,I            ;store


        The SAIL statement  If S =  "A" THEN S1; (S  a string, S1  a state-
ment) compiles as:

                HRRZ  AC,S
                JUMPE AC,PLACE
                MOVE  AC,S+1
                ILDB  AC,AC
        PLACE:  CAIE  AC,101
                JRST  BEYOND
                |


                                    27
SAIL and PDP10 Machine Language                            January 26, 1976





                |(Code for S1)
                |
        BEYOND:



        III.5    Strings in Procedure Calls
                 Strings in Procedure Calls
                 Strings in Procedure Calls
                 Strings in Procedure Calls


        To  cope  with  string  procedures  (especially  those   which  are
recursive) and for garbage collection SAIL makes use of a  string push-down
stack.  AC 16 is used  for this and is traditionally labeled  "SP".  Recall
the two  words assembled by  "STRING S;".   These are what  go onto  the SP
stack when needed.

        Example: Consider the following SAIL procedure

SIMPLE INTEGER PROCEDURE HOWMANY(STRING S; INTEGER CHAR)
BEGIN
    INTEGER CNT,C;
    CNT ← 0;
    WHILE LENGTH(S) DO
        BEGIN
            C ← LOP(S);
            IF C = CHAR THEN CNT ← CNT + 1;
        END;
    RETURN(CNT);
END;

A call on this procedure involves two arguments, 1 a value string S,
and the other an integer CHAR.  The code for

I ← HOWMANY(T,C);

is therefore

        PUSH    SP,S
        PUSH    SP,S+1
        PUSH    P,C
        PUSHJ   P,HOWMANY
        MOVEM   A,I

        String  arguments are  passed to  procedures on  the SP  stack, and
likewise string results are returned  on the SP stack.  Thus,  consider the
procedure:

STRING PROCEDURE UPPER(STRING S);
BEGIN
STRING U;
U ← NULL;


                                    28
SAIL and PDP10 Machine Language                            January 26, 1976





WHILE (CHAR ← LOP(S)) DO
    U ← U & (IF "a" LEQ C LEQ "z" THEN C -'40 ELSE C);
RETURN(U);
END;

The call

T ← UPPER(V);

compiles as

        PUSH    SP,V
        PUSH    SP,V+1
        PUSHJ   P,UPPER
        POP     SP,T+1
        POP     SP,T

Notice that the POPes are in reverse order than the PUSHes.

        Exercise.  Try compiling the above procedure for UPPER, identifying
        Exercise
        Exercise
        Exercise
the  WHILE loop,  the LOP  assignment, and  the IF...THEN  test  within the
concatenation operator.



        III.6    Array Implementation
                 Array Implementation
                 Array Implementation
                 Array Implementation


        Arrays were discussed a  bit previously. The simplest example  of a
SAIL array is an outer block array (or an "OWN" array, which works the same
way) with one dimension and  constant bounds beginning at 0,  e.g. A[0:10],
which is declared of type integer.  In this case the compiler can  and will
allocate 11 contiguous words of memory for the array, assigning the label A
to A[0].  Thus A[n] can be found at A+n.

        The code

J ← A[i]

is implemented as

        MOVE    AC,I
        MOVE    AC,A(AC)
        MOVEM   AC,J


        The situation becomes a little more complex when the lower bound of
the array starts at a positive integer, as in A[1:10].  It is  more complex
because if we  assigned the label A  to the location containing  A[1], then



                                    29
SAIL and PDP10 Machine Language                            January 26, 1976





A[n] would be found at location A+n-1 rather than at A+n.  So  the compiler
produces an offset in this case,  by assigning the label A to  the location
where A[0] would have been had the upper bound remained fixed where  it is.
Thus knowing A,  we know where  A[n] is stored  in memory.  Of  course code
like

        MOVE AC,I
        SUBI AC,1
        MOVE AC,A(AC)

could have been  produced, but it is  more efficient to calculate  A-1 once
and then produce code like

        MOVE AC,I
        MOVE AC,[A-1](AC)


        The situation  becomes rapidly more  complex, when for  example, an
array is declared within a procedure.  If A is the array, then in this case
location A is used to store the beginning of the array.  (Note that in such
cases the array  is re-created each time  the procedure is entered  at run-
time and  destroyed each time  the procedure is  exited.  Thus,  unless the
program is already quite  large it is often  better to declare an  array in
the outer block  of a SAIL  program.) In front of  a procedure in  which an
array is declared one will find something like

                PUSHJ P,ARMAK
                MOVEM 1,A

where ARMAK is a SAIL function  which takes care of the details  of finding
space and so on.  Since the  "low segment" of the program will  probably be
in a different state each time  the procedure is entered, the array  may be
stored in a different block of words upon each entry into the procedure.

        Now consider how J ← A[I] will be implemented within a procedure:

                MOVE  AC,A
                SUB   AC,[1]    ; get the offset correct
                ADD   AC,I      ; when this is executed AC has the addr
                MOVE  AC,(AC)
                MOVEM AC,J      ; and move the value into J


        Another degree  of complexity  is added when  the array  bounds are
variable, e.g. consider a procedure which includes m,n among  its reference
variables and includes a declaration  like ARRAY A[m:n];.  In this  case, A
will still point to  the first element of the  array, but above A  (i.e. in
smaller numbered addresses) will be stored information on the  array bounds
and so forth.



                                    30
SAIL and PDP10 Machine Language                            January 26, 1976





        In SAIL,  unless an  array is declared  "SAFE", bounds  checking is
performed.  This would be  implemented as something like the  following for
an array A[1:10]

                MOVE  AC,J      ; J is the bound being checked
                CAIL  AC,1
                CAILE AC,10
                  ERR           ;Special "UUO" to handle array error
                MOVE  AC,ORIGIN(AC)
                MOVEM AC,I


        Exercise Write a "machine language" version of
        Exercise
        Exercise
        Exercise

BEGIN
    INTEGER I,J,K;
    INTEGER ARRAY A[1:10];
        A[2] ← 4;
        I ← A[2];
        J ← 3;
        I ← A[J];
        FOR I ← 1 STEP 1 UNTIL 11 DO A[I] ← I;
END;

Then, compare it to the code produced by the SAIL compiler.



























                                    31
SAIL and PDP10 Machine Language                            January 26, 1976





                                Appendix I
                                Appendix I
                                Appendix I
                                Appendix I

                Machine Instructions Commonly Used by SAIL
                Machine Instructions Commonly Used by SAIL
                Machine Instructions Commonly Used by SAIL
                Machine Instructions Commonly Used by SAIL




        The following  machine instructions are  commonly used by  the SAIL
compiler.

MOVE
MOVEI
MOVEM
MOVSI

ADD
ADDI
ADDM

SUB
SUBM

IDIV
IDIVI

IMUL
IMULI

JRST
JUMPsuffix
SKIPsuffix
CAMsuffix
CAIsuffix

AOJA
SOJA

FADR
FSBR
FMPR
FDVR

HRRZ
HRRZM
HRRO
HRROI

PUSH
POP
PUSHJ


                                    32
SAIL and PDP10 Machine Language                            January 26, 1976





POPJ



















































                                    33